$(document).ready(function() {
  var ftBase = "https://www.googleapis.com/fusiontables/v1/"
  var googleApiKey = "&key=AIzaSyAypVGqTVOOjYsayqWYSQhu-vme30maXUQ";
  var cb = "&callback=?";
  var metaTable;
  var flightLogs = [];
  var mapCenter = new google.maps.LatLng(5, -20);
  // interval between two waypoints, currently hard coded
  var IVAL = 10;

  function flash(wp, time) {
    console.log(wp);
    wp.setOptions({ fillColor: '#FFFFFF' });
    setTimeout(function() {
      wp.setOptions({ fillColor: wp.fl.getColor() });
    }, 1000);
  }

  function highlightNextWaypoint(vid, seconds) {
    console.log("Looking for next waypoint in " + vid + " after " + seconds);
    var skip = Math.floor(seconds / IVAL) * IVAL + IVAL;
    console.log("next waypoint at " + skip);
    
    for (var i in flightLogs) {
      fl = flightLogs[i];
      if (fl.getVideo() == vid) {
        console.log("Found flightlog");
        for (var j in fl.waypoints) {
          var wp = fl.waypoints[j];
	  // console.log(wp);
	  var myskip = wp.fl.getRowSkip((+wp.index));
          console.log("myskip = " + myskip);
          if (skip == myskip) {
            console.log("found waypoint!");
	    flash(wp, 10);
          }
        }
      }
    }
  }

  function getMetaTable() {
    var sql = "query?sql=SELECT * FROM 1otwpfXzMnLUnGDAGIb78DjHuYMtbQzqK4Moh6gw";
    var url = ftBase + sql + googleApiKey + cb;
    $.getJSON(url, function(response) {
      console.log(response);
      metaTable = response;
      getFlightPlans(metaTable);
    });
  }

  getMetaTable();
  var FlightPlan = function(base) {
    this.base = base;
  }
 
  FlightPlan.prototype = {
    getName : function() {
      return this.base[0];
    },
    getFTid : function() {
      return this.base[1];
    },
    getColor : function() {
      return this.base[2];
    },
    getVideo : function() {
      return this.base[3];
    },
    getIndex : function() {
      return this.index;
    },
    setIndex : function(i) {
      this.index = i;
    },
    setResponse : function(r) {
      this.response = r;
    },
    getRows: function() {
      return this.response.rows;
    },
    getRow: function(i) {
      return this.response.rows[i];
    },
    getRowSkip: function(i) {
      return this.getRow(i)[1];
    }
  }

  function getFlightPlanTable(fp, i) {
    // TODO load names from table
    var published = fp[4];
    if (published == "false") {
      console.log("skipping flight path " + fp[0]);
      return;
    }
    var flightPlan = new FlightPlan(fp);
   
    flightPlan.setIndex(i);
    var sql = "query?sql=SELECT * FROM " + flightPlan.getFTid();
    var url = ftBase + sql + googleApiKey + cb;
  
    $.getJSON(url, function(response) {
      console.log(response);
      flightPlan.setResponse(response);
      flightLogs[i] = flightPlan;
    });
  };

  function getFlightPlans(metaTable) {
    console.log(metaTable.rows);
    for (i in metaTable.rows) {
      getFlightPlanTable(metaTable.rows[i], i);
    }
  };
  

  // Projection for flat world as on google groups discussed
  // https://groups.google.com/forum/?fromgroups=#!msg/google-maps-js-api-v3/UEIbpcTdMHs/RQv1hoWzpiAJ
  
  function StratisProjection() {
    var EUCLIDEAN_RANGE = 256;
    this.pixelOrigin_ = new google.maps.Point(EUCLIDEAN_RANGE / 2,
  			                      EUCLIDEAN_RANGE / 2);
    this.pixelsPerLonDegree_ = EUCLIDEAN_RANGE / 360;
    this.pixelsPerLonRadian_ = EUCLIDEAN_RANGE / (2 * Math.PI);
    this.scaleLat = 4.5;        // Height - multiplication scale factor
    this.scaleLng = 4.5;        // Width - multiplication scale factor
    this.offsetLat = 0;        // Height - direct offset +/-
    this.offsetLng = 0;        // Width - direct offset +/-
  
    this.worldOrigin_ = new google.maps.Point(0,0);
  
  };
  
  StratisProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {
    var point = opt_point || new google.maps.Point(0, 0);
  
    var origin = this.pixelOrigin_;
    point.x = (origin.x + (latLng.lng() + this.offsetLng ) *
 	       this.scaleLng * this.pixelsPerLonDegree_);
    // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
    // 89.189.  This is about a third of a tile past the edge of the world tile.
    point.y = (origin.y + (-1 * latLng.lat() + this.offsetLat ) *
              this.scaleLat * this.pixelsPerLonDegree_);
    return point;
  };
  
  StratisProjection.prototype.fromPointToLatLng = function(point, noWrap) {
    var me = this;
  
    var origin = me.pixelOrigin_;
    var lng = (((point.x - origin.x) / me.pixelsPerLonDegree_) /
              this.scaleLng) - this.offsetLng;
    var lat = ((-1 *( point.y - origin.y) / me.pixelsPerLonDegree_) /
              this.scaleLat) - this.offsetLat;
    return new google.maps.LatLng(lat , lng, true);
  };

  // Normalizes the coords that tiles repeat across the x axis (horizontally)
  // like the standard Google map tiles.
  function getNormalizedCoord(coord, zoom) {
    var y = coord.y;
    var x = coord.x;
  
    // tile range in one direction range is dependent on zoom level
    // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc
    var tileRange = 1 << zoom;
  
    // don't repeat across y-axis (vertically)
    if (y < 0 || y >= tileRange) {
      return null;
    }
  
    if (x < 0 || x >= tileRange) {
      return null;
    }
  
    return {
      x: x,
      y: y
    };
  };
  
  // Map setup
  var mapTypeOptions = {
    tileSize: new google.maps.Size(256,256),
    maxZoom: 4,
    minZoom: 0,
    getTileUrl: function(coord, zoom) {
      var normalizedCoord = getNormalizedCoord(coord, zoom);
      if (!normalizedCoord) {
        return null;
      }
      var bound = Math.pow(2, zoom);
      var url = "http://tspindler.de/tiles/tile_" + zoom + "_" +
                   normalizedCoord.x + "-" + normalizedCoord.y + ".png";
      //console.log("Asking for " + url);
      return url;
    },
    name: 'Stratis'
  };
  
  function scaleNeighbours(wpc, mode) { 
    // config for waypoint marker
    var scale = 2;
    console.log(wpc);
    console.log(mode);
    if (wpc.index > 0) {
      var j = (+wpc.index) - 1.0;
      var r = wpc.fl.waypoints[j].getRadius();
      if (mode == "in") {
        wpc.fl.waypoints[j].setRadius(r / scale);
      } else {
        wpc.fl.waypoints[j].setRadius(r * scale);
      }
    }
    if (wpc.index < wpc.fl.waypoints.length - 1) {
      var j = (+wpc.index) + (+1);
      var r = wpc.fl.waypoints[j].getRadius();
      if (mode == "in") {
        wpc.fl.waypoints[j].setRadius(r * scale);
      } else {
        wpc.fl.waypoints[j].setRadius(r / scale);
      }
    }
  }

  function controlFlightLog(fl, ctl) {
    var i = fl.getIndex();
    var ctlName = "cb" + i;
    console.log( "Index is " + i + " for " + ctlName + " " + fl.getName());
    var ret = "<input type='checkbox' id='" + ctlName + "' name='" + i +
                   "' value='" + i + "' checked>" + fl.getName() + "<br>";
    ret = "<font class='ctlfont' color='" + fl.getColor() + "'>" + ret + "</font>";
    console.log(ret);
    $(ctl).append(ret);
    $("#" + ctlName).change( function() {
       var fl = flightLogs[this.value];
       for (var j in fl.waypoints) {
	 var wp = fl.waypoints[j];
	 wp.setVisible(this.checked);
       }
       fl.line.setVisible(this.checked);
    } );
  }
 
  var stratisMapType = new google.maps.ImageMapType(mapTypeOptions);
  stratisMapType.projection = new StratisProjection();
  
  // TODO fix this offset stuff
  // terrible idea to transform the GPS coords like that...
  var lngOffset = 41;
  var latOffset = 41;
  
  function initialize() {
    var mapOptions = {
      backgroundColor: '#B7CBe6',
      center: mapCenter,
      zoom: 2,
      mapTypeControl: false,
      streetViewControl: false,
      mapTypeControlOptions: {
        mapTypeIds: ["stratis"]
      },
      zoomControl: true,
      zoomControlOptions: {
          position: google.maps.ControlPosition.LEFT_BOTTOM
      },
      panControl: true,
      panControlOptions: {
          position: google.maps.ControlPosition.LEFT_BOTTOM
      },
      scaleControl: false,
      scaleControlOptions: {
          position: google.maps.ControlPosition.TOP_RIGHT
      }
    };
  
    var map = new google.maps.Map(document.getElementById("map"),
        mapOptions);
    map.mapTypes.set('stratis', stratisMapType);
    map.setMapTypeId('stratis');
  
    google.maps.event.addListener(map, 'click', function(event) {
      console.log('clicked');
      var latLng = event.latLng;
      console.log(latLng.lat() + " " + latLng.lng());
    });

    for (var i in flightLogs) {
      var fl = flightLogs[i];
      console.log("setting up flight log " + fl.getName());
      console.log(fl);
      var wps = [];
      for (var j in fl.getRows()) {
        var wp = fl.getRow(j);
        console.log(wp);
	console.log(wp[2] + wp[3]);
        var wpCircle = {
          strokeColor: fl.getColor(),
          strokeOpacity: 0.8,
          strokeWeight: 1,
          fillColor: fl.getColor(),
          fillOpacity: 0.35,
          map: map,
          center: new google.maps.LatLng(wp[3]/100 - latOffset,
                                         wp[2]/100 - lngOffset),
          radius: 100000,
          index: j,
          fl: fl,
        };
        var wpc = new google.maps.Circle(wpCircle);
        wps.push(wpc);
        google.maps.event.addListener(wpc, 'mouseover', function(event) {
          var msg = document.getElementById("msg");
          var skip = this.fl.getRowSkip(this.index);
         
          msg.innerHTML = "Displaying video " + this.fl.getName() +
  		        " starting at " + skip + " seconds.";
	  scaleNeighbours(this, "in");
        } );
        google.maps.event.addListener(wpc, 'mouseout', function(event) {
	  console.log('mouseout');
          var msg = document.getElementById("msg");
          msg.innerHTML = "No message";
	  scaleNeighbours(this, "out");
        } );
        google.maps.event.addListener(wpc, 'click', function(event) {
          var video = this.fl.getVideo();
          var i = this.index;
          var skip = this.fl.getRowSkip(i);
          console.log("Mouse over: " + i + ":" + skip);
          player.pauseVideo();
          player.loadVideoById(video, skip, "small");
        } );
      }
      fl.waypoints = wps;
      var pts = [];
      for (i in wps) {
        var wp = wps[i];
        console.log(wp.getCenter());
        pts.push(wp.getCenter());
      }
      var line = new google.maps.Polyline({
        path: pts,
        strokeColor: fl.color,
        strokeOpacity: 0.8,
        strokeWeight: 1,
        map: map,
      });
      fl.line = line;
      controlFlightLog(fl, "#ctlmsg");
    } // end setting up flight log
    var ctr = "<font class='ctlfont'><input type='button' id='ctr'>Center map</font><br>";
    $( "#control" ).append(ctr);
    $( "#ctr" ).click(function() { console.log("centering"); map.setCenter(mapCenter); });

  };

  $( "#control" ).dialog({ title: "Controls", autoOpen: true, width: "300px", position: "right-10", zIndex: 10, dialogClass: "ctl" });
  $( "#msgBox" ).dialog({ title: "Messages", autoOpen: true, width: "300px", position: "right-10 bottom-20", zIndex: 10, dialogClass: "msg" });
  $( "#opener" ).click(function() {
    $( "#control" ).dialog( "open" );
  });
  $( "#opener" ).click(function() {
    $( "#msgBox" ).dialog( "open" );
  });

  var msg = document.getElementById("msg");
  // endless function to monitor state of youtube player and update map accordingly
  function playerState() {
    setTimeout(function() {
      var state = player.getPlayerState();
      if (state == 1) {
        var seconds = player.getCurrentTime();
  	var url = player.getVideoUrl();
        var videoid = url.substring(url.lastIndexOf("=")+1, url.length);
        msg.innerHTML = "Playback running for " + seconds +
			" for " + videoid + 
			 ".<br>" + msg.innerHTML;
        console.log("displayed state");
  	// advanced hackery, evil evil
	highlightNextWaypoint(videoid, seconds);
      }
      playerState();
    } ,5000);
  }
  playerState();
  google.maps.event.addDomListener(window, 'load', initialize);

});
